#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "totaldef.h"
#include "totalpoint.h"
#include <QtNetwork>
#include <QString>
#include <QMessageBox>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    firstPlayer = false;//初始化先手置否

    //ui->btnHuiQi->setDisabled(true);//初始化悔棋按键无效

    //初始化棋局 17x17
    myPt = new myPoint*[17];
    for(int i = 0;i < 17;i++)
    {
        myPt[i] = new myPoint[19];
    }

    for(int i = 0,x = 25;i < 17&&x <= 585;i++,x += 35)
    {
        for(int j = 0,y = 25;j < 17&&y <= 585;j++,y += 35)
        {
           myPt[i][j].set(x,y,SPACE);
        }
    }

    //设置初始信息
    tempPt = new myPoint(-1,-1,0);
    color = -1;
    runState = 0;
    whoDo = 0;

    //设置连接的服务器ip及端口
    //serAddr = "125.217.40.51";
    //serPort = 7001;

    //logIn();

    //预留一步悔棋信息
    lastPtBlack = new myPoint(-1,-1,BLACK);
    lastPtWhite = new myPoint(-1,-1,WHITE);

    sendPt.mask = LaoZi;
    sendPt.x = -1;
    sendPt.y = -1;
    sendPt.color = -1;
/*
 *客户端对套接字的初始化及信号槽的连接放在login函数生效之后使用
//    tcpClient = new QTcpSocket(this);

//    connect(tcpClient,SIGNAL(readyRead()),this,SLOT(readMessage()));
//    connect(tcpClient,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(displayError(QAbstractSocket::SocketError)));
//    connect(this,SIGNAL(connectToServer()),this,SLOT(newConnect()));
*/
    //named ui slots
    connect(ui->btnStartPre,SIGNAL(clicked()),this,SLOT(startPre()));
    connect(ui->btnHuiQi,SIGNAL(clicked()),this,SLOT(huiQi()));
    connect(ui->btnLogin,SIGNAL(clicked()),this,SLOT(logIn()));
    //打开客户端时发送连接服务器信号
    //emit connectToServer();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    //painter.setRenderHint(QPainter::Antialiasing, true);
    painter.setBrush(QColor(134,85,10));//*/Qt::lightGray);//238,190,34//124,75,00
    painter.drawRect(15, 15, 580, 580);
    //画棋盘
    for (int i = 0;i < 17;i++)
    {
        //横线 起点坐标-终点坐标，间隔为35
        painter.drawLine(25, 25 + i * 35, 585, 25 + i * 35);
        //竖线 同上
        painter.drawLine(25 + i * 35, 25, 25 + i * 35, 585);
    }
    QPainter bwPainter(this);
    //设置反走样
    bwPainter.setRenderHint(QPainter::Antialiasing, true);
    if(color == BLACK)
    {
        bwPainter.setBrush(Qt::black);
        bwPainter.drawEllipse(695, 480, 30, 30);
    }
    else if(color == WHITE)
    {
        bwPainter.setBrush(Qt::white);
        bwPainter.drawEllipse(695, 480, 30, 30);
    }
    for (int x = 0; x < 17; x++)
    {
        for (int y = 0; y < 17; y++)
        {
            if (myPt[x][y].color == BLACK ) //黑棋子
            {
                bwPainter.setBrush(Qt::black);
                bwPainter.drawEllipse(myPt[x][y].x-15,
                                      myPt[x][y].y-15, 30, 30);
            }
            else if (myPt[x][y].color == WHITE ) //白棋子
            {
                bwPainter.setBrush(Qt::white);
                bwPainter.drawEllipse(myPt[x][y].x-15,
                                      myPt[x][y].y-15, 30, 30);
            }
        }
    }
    //QMainWindow::paintEvent(e);
}

void MainWindow::mouseReleaseEvent(QMouseEvent *e)
{
    //runState = myRunning;whoDo = IDo;color = BLACK;firstPlayer = true;// test
    //ui->btnHuiQi->setDisabled(true);//本方落子回合可以发起对上一轮双方落子悔棋请求
    int final_x,final_y;//最后的落子点坐标(0,0)~(16,16)
    if(e->button() == Qt::LeftButton&&runState == myRunning&&whoDo == IDo)
    {
        int rx,ry;//鼠标点击原始坐标
        rx = e->x();
        ry = e->y();
        QString sx,sy;
        sx = QString::number(rx);
        sy = QString::number(ry);
        //QMessageBox::information(this,"原始坐标",sx+","+sy,NULL);
        //鼠标点击在棋盘区域内
        if(e->x() >= 20 && e->x() < 590 && e->y() >= 20 && e->y() < 590)
        {
            final_x = (e->x() - 25 + 17) / 35;
            final_y = (e->y() - 25 + 17) / 35;
            sx = QString::number(final_x);
            sy = QString::number(final_y);
            //QMessageBox::information(this,"转换坐标",sx+","+sy,NULL);
        }
        else
        {
            QMessageBox::information(this,"point message","not in right area",NULL);
            return;
        }
        //定义标识
        bool sendWant = false;
        bool IWin = false;
//        for(int i = 0;i < 17;i++)
//        {
//            for(int j = 0;j < 17;i++)
//            {
//                if((tempPt->x==myPt[i][j].x&&tempPt->y==myPt[i][j].y)||((tempPt->x<=myPt[i][j].x+10)&&(tempPt->x>=myPt[i][j].x-10)&&(tempPt->y<=myPt[i][j].y+10)&&(tempPt->y>=myPt[i][j].y-10)))
//                {
//                    ///???///
//                }
//            }
//        }
        if(myPt[final_x][final_y].color == SPACE)
        {
            sendPt.x = final_x;
            sendPt.y = final_y;
            sendPt.color = color;
            ui->textEdit->append("本方玩家落子点:"+sx+","+sy);
            whoDo = HeDo;//本方落子之后对方落子
            sendWant = true;
            ui->textEdit->append("等待对方落子");\
            //临时置胜负判断位
            myPt[final_x][final_y].color = color;
            if(winner(sendPt.x,sendPt.y,sendPt.color))
            {
                ui->textEdit->append("本方玩家获胜");
                IWin = true;
            }
            //恢复临时判断位
            myPt[final_x][final_y].color = SPACE;
            update();
        }
        else
        {
            QMessageBox::information(this,"提示","此处已有落子",tr("是"));
        }
        //向服务器发送棋局信息
        if(sendWant)
        {
            char send[5] = "";
            send[0] = sendPt.mask;
            if(IWin)
            {
                send[0] = char(ULost);
            }
            //防止数组传0
            if(sendPt.x == 0)
            {
                send[2] = 'A';
                ui->textEdit->append("will send a 0 point");
            }
            else
            {
                send[2] = sendPt.x;
            }
            send[1] = sendPt.color;
            send[3] = sendPt.y;
            qDebug()<<"a send message location"<<int(send[2])<<","<<int(send[3])<<endl;
            tcpClient->write(send);
            tcpClient->waitForBytesWritten();
            tcpClient->flush();
            ui->textEdit->append("本方向服务器发送落子信息");
        }
    }
}

//玩家登入服务器
void MainWindow::logIn()
{
    QString serveraddr, serverport;
    serveraddr = ui->lineEdit->text();
    serverport = ui->lineEdit_2->text();
    if(serveraddr == NULL||serverport == NULL)
    {
        QMessageBox::information(this,"提示","填写服务器IP及端口",NULL);
        return;
    }
    serAddr = serveraddr;
    serPort = serverport.toInt();

    tcpClient = new QTcpSocket(this);

    ///////
    ///signal and slot connect function add at here
    ///////

    connect(tcpClient,SIGNAL(readyRead()),this,SLOT(readMessage()));
    connect(tcpClient,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(displayError(QAbstractSocket::SocketError)));
    connect(this,SIGNAL(connectToServer()),this,SLOT(newConnect()));

    //登入客户端时发送连接服务器信号
    emit connectToServer();
    ui->textEdit->append("客户端连接服务器成功");
    ui->btnLogin->setDisabled(true);
}

//玩家开始准备
int MainWindow::startPre()
{
    mask = PreStart;
    char m = char(mask);
    char buf[3];
    buf[0] = m;
    for(int i = 1;i < 3;i++)
    {
        buf[i] = '\0';
    }
    tcpClient->write(buf);
    tcpClient->waitForBytesWritten();
    tcpClient->flush();
    ui->btnStartPre->setDisabled(true);
    return 0;
}

//悔棋事件函数
/*悔棋函数使用初始化的两个二维数组完成，所以双方悔棋请求必须有落子间隔*/
int MainWindow::huiQi()
{
    if(/*runState != myRunning&&*/whoDo == HeDo)
    {
        QMessageBox::information(this,"提示","非本方回合，无法悔棋",NULL);
        return 1;
    }
    if(lastPtBlack->x<0||lastPtWhite->x<0)
    {
        QMessageBox::information(this,"提示","落子数不足，无法悔棋",NULL);
        return 2;
    }
    char mask0 = char(HuiQiCmd);
    char mask1 = char(HuiQi_Want);
    char buf[3] = "";
    buf[0] = mask0;
    buf[1] = mask1;
    tcpClient->write(buf);
    tcpClient->waitForBytesWritten();
    tcpClient->flush();
    ui->textEdit->append("本方发送悔棋请求");
    whoDo = HeDo;
    return 0;
}

//退出
int MainWindow::quitGame()
{
    //QApplication* app;
    //app->quit();//exit(0);
    return 0;
}

//连接服务器函数
void MainWindow::newConnect()
{
    tcpClient->connectToHost(serAddr,serPort);
}

//接收服务器发送消息
void MainWindow::readMessage()
{
    const int buflength = 20;
    char buf[buflength] = "";
    memcpy(buf,tcpClient->readAll().data(),buflength);
    int mask0 = int(buf[0]);
    bool twoMsg = false;
    char buf2[3] = "";
    buf2[0] = buf[5];
    buf2[1] = buf[6];
    int bs = int(buf2[0]);
    int s5 = 5;
    if(bs == s5)
    {
        twoMsg = true;
    }
    //还原0操作
    if(buf[2] == 'A')
    {
        buf[2] = 0;
    }
    qDebug("%d %d %d %d %d %d %d",buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6]);
    //收到服务器携带两类信息1
    if(twoMsg)
    {qDebug("two msg");}
    switch(mask0)
    {
    case Cmd:
    {
        int maskcmd = int(buf[1]);  //Cmd;
        switch(maskcmd)
        {
        case StartDo:
        {
            ui->textEdit->append("服务器提示本方落子");
            whoDo = IDo;
            if(runState!=myRunning)
            {
                runState = myRunning;
            }
            //后手持白子
            if(firstPlayer!=true)
            {
                color = WHITE;
            }
            break;
        }
        case URfisrt:
        {
            ui->textEdit->append("本机持黑先行");
            whoDo = IDo;
            runState = myRunning;
            firstPlayer = true;
            color = BLACK;
            break;
        }
        }
        break;
    }
    //收到落子信息
    case LaoZi_Ok:
    {
        ui->textEdit->append("服务器收到新的落子信息");
        //qDebug("servre  kown   laozi ");
        int tempcolor = int(buf[1]);
        int x = int(buf[2]);
        int y = int(buf[3]);
        myPt[x][y].color=tempcolor;
        if(myPt[x][y].color==WHITE)
        {
            lastPtWhite->setXY(x,y);
        }
        else if(myPt[x][y].color==BLACK)
        {
            lastPtBlack->setXY(x,y);
        }
        update();
        break;
    }
    case HuiQiCmd:   //from other
    {
        short mask1 = short(buf[1]);
        switch(mask1)
        {
        case HuiQi_Want:
        {
            //悔棋用数组
            char bufh[3] = "";
            bufh[0] = char(mask0);
            bool iAgreeHuiqi=false;
            if (!(QMessageBox::information(this,tr("悔棋"),tr("对方提出悔棋，是否同意"),tr("是"),tr("否"))))
            {
                iAgreeHuiqi=true;
            }
            if(iAgreeHuiqi)
            {
                bufh[1] = char(HuiQi_Agree);
                myPt[lastPtWhite->x][lastPtWhite->y].setColor(SPACE);
                myPt[lastPtBlack->x][lastPtBlack->y].setColor(SPACE);
            }
            else
            {
                bufh[1]=char(HuiQi_Disagree);
            }
            tcpClient->write(bufh,3);
            tcpClient->waitForBytesWritten();
            tcpClient->flush();
            update();
            break;
        }
        case HuiQi_Ok:
        {
            myPt[lastPtWhite->x][lastPtWhite->y].setColor(SPACE);
            myPt[lastPtBlack->x][lastPtBlack->y].setColor(SPACE);
            ui->textEdit->append("悔棋操做成功");
            whoDo=IDo;
            //更新棋局
            update();
            break;
        }
        case HuiQi_Fail:
        {
            ui->textEdit->append("悔棋操作失败");
            whoDo=IDo;
            break;
        }
        default:
        {
            break;
        }
        }
        break;
    }
    case UWin:
    {
        //ui->textEdit->append("本方获胜");
        int tempcolor = int(buf[1]);
        int x = int(buf[2]);
        int y = int(buf[3]);
        myPt[x][y].color = tempcolor;
        if(myPt[x][y].color==WHITE)
        {
            lastPtWhite->setXY(x,y);
        }
        else if(myPt[x][y].color==BLACK)
        {
            lastPtBlack->setXY(x,y);
        }
        update();
        QMessageBox::information(this,tr("游戏结果"),tr("游戏结束，本方获胜"),tr("是"));
        ui->textEdit->append("本方获胜");
        runState = myStopped;
        whoDo = HeDo;
        firstPlayer = false;
        for(int i = 0;i < 17;i++)
        {  for(int j = 0;j < 17;j++)
            {
                myPt[i][j].setColor(SPACE);
                // qDebug("myPoint  setColor %d %d ",i,j);
            }
        }
        update();
        ui->btnStartPre->setEnabled(true);
        break;
    }
    case ULost:
    {
        qDebug("servre kown laozi and U lost");
        int tempcolor = int(buf[1]);
        int x = int(buf[2]);
        int y = int(buf[3]);
        myPt[x][y].color = tempcolor;

        if(myPt[x][y].color==WHITE)
        {
            lastPtWhite->setXY(x,y);
        }
        else if(myPt[x][y].color==BLACK)
        {
            lastPtBlack->setXY(x,y);
        }
        update();
        QMessageBox::information(this,tr("游戏结果"),tr("对方获胜，请再接再厉"),tr("是"));
        ui->textEdit->append("对方获胜");
        runState = myStopped;
        whoDo = HeDo;
        firstPlayer = false;
        for(int i = 0;i < 17;i++)
        {  for(int j = 0;j < 17;j++)
            {
                myPt[i][j].setColor(SPACE);
            }
        }
        update();
        ui->btnStartPre->setEnabled(true);
        break;
    }
    default:
    {
        break;
    }
    }
    //处理char[5]char[6]携带的开局消息
    if(twoMsg)
    {
        int mask20 = int(buf2[0]);
        switch(mask20)
        {
        case Cmd:
        {
            int maskcmd2 = int(buf2[1]);  //Cmd;
            switch(maskcmd2)
            {
            case StartDo:
            {
                qDebug("server tell me to put down point");
                ui->textEdit->setText("you should to click a point");
                whoDo = IDo;
                if(runState!=myRunning)
                {
                    runState = myRunning;
                }
                if(firstPlayer!=true)
                {
                    color = WHITE;
                }
                break;
            }
            case URfisrt:
            {
                qDebug("server tell me is First to put down point");
                ui->textEdit->setText("you should to click a point");
                whoDo = IDo;
                runState = myRunning;
                firstPlayer = true;
                color = BLACK;
                break;
            }
            }
            break;
        }
        case LaoZi_Ok:
        {
            qDebug("servre  kown   laozi ");
            ui->textEdit->append("服务器收到落子信息");
            int tempcolor = int(buf[1]);
            int x = int(buf[2]);
            int y = int(buf[3]);
            myPt[x][y].color = tempcolor;
            if(myPt[x][y].color==WHITE)
            {
                lastPtWhite->setXY(x,y);
            }
            else if(myPt[x][y].color==BLACK)
            {
                lastPtBlack->setXY(x,y);
            }
            update();
            break;
        }
        default:
        {
            break;
        }
        }
    }
}


void MainWindow::displayError(QAbstractSocket::SocketError)
{
    ui->textEdit->append("连接服务器出错，请重试");
    ui->btnLogin->setEnabled(true);
    qDebug("tcp error");
}
bool MainWindow::winner(int posX, int posY, int TheColor)
{
    //WIN_COUNT   			   5
    //BOARD_SIZE              17

    //计算后的X轴起始点("左上到右下的斜向"时为左上点X坐标,"右上到左下的斜向"时为右上点X坐标)
    int startX = 0;
    //计算后的Y轴起始点("左上到右下的斜向"时为左上点Y坐标,"右上到左下的斜向"时为左下点Y坐标)
    int startY = 0;
    //计算后的X轴终止位("左上到右下的斜向"时为右下点X坐标,"右上到左下的斜向"时为左下点X坐标)
    int endX = BOARD_SIZE - 1;
    //计算后的Y轴终止位("左上到右下的斜向"时为右下点Y坐标,"右上到左下的斜向"时为右上点Y坐标)
    int endY = BOARD_SIZE - 1;
    //posX - WIN_COUNT + 1 的值
    int minX = 0;
    //posY - WIN_COUNT + 1 的值
    int minY = 0;
    //posX + WIN_COUNT - 1 的值
    int maxX = BOARD_SIZE - 1;
    //posY + WIN_COUNT - 1 的值
    int maxY = BOARD_SIZE - 1;
    int sameCount = 0;

    //calculate min X position and Y position
    minX = posX - WIN_COUNT + 1;
    startX = minX < 0 ? 0 : minX;
    minY =posY - WIN_COUNT + 1;
    startY = minY < 0 ? 0 : minY;

    //calculate max X position and Y position
    maxX = posX + WIN_COUNT - 1;
    endX = maxX > BOARD_SIZE - 1 ? BOARD_SIZE - 1 : maxX;
    maxY =posY + WIN_COUNT - 1;
    endY = maxY > BOARD_SIZE - 1 ? BOARD_SIZE - 1 : maxY;

    int  Board_color[17][17];
    for(int xxx=0;xxx<17;xxx++)
    {
        for(int yyy=0;yyy<17;yyy++)
        {
            Board_color[xxx][yyy] = myPt[xxx][yyy].color;
        }
    }
    //Col position chess check 计算横向是否胜
    for(int i = startY; i < endY; i++)
    {
        if(Board_color[posX][i] == TheColor && Board_color[posX][i+1] == TheColor)
        {
            sameCount++;
        }
        else if(sameCount < WIN_COUNT - 1)
        {
            sameCount = 0;
        }
    }
    //Vol position chess check 计算纵向是否胜
    for(int i = startX; i < endX; i++)
    {
        if(Board_color[i][posY] == TheColor && Board_color[i+1][posY] == TheColor)
        {
            sameCount++;
        }
        else if(sameCount < WIN_COUNT - 1)
        {
            sameCount = 0;
        }
    }
    //Inclined position chess check
    //Left top to right bottom 计算左上到右下的斜向是否胜,这里要判断所下子是否在13区域以外的其他区域,以相应的减少斜向X和Y坐标的起始位和终止位.
    //calculate start X position and Y position
    //startX
    if (minX < 0)
    {
        //area 1
        if(posX > posY)
        {
            startX = posX - posY;
        }
        //area 2,3,4,9
        else
        {
            startX = 0;
        }
    }
    //area 7,8,12
    else if(minY < 0)
    {
        startX = posX - posY;
    }
    //area 5,6,10,11,13
    else
    {
        startX = minX;
    }

    //startY
    if (minY < 0)
    {
        //area 2
        if(posX < posY)
        {
            startY = posY - posX;
        }
        //area 1,7,8,12
        else
        {
            startY = 0;
        }
    }
    //area 3,4,9
    else if(minX < 0)
    {
        startY = posY - posX;
    }
    //area 5,6,10,11,13
    else
    {
        startY = minY;
    }

    //calculate end X position and Y position
    //endX
    if (maxX > BOARD_SIZE - 1)
    {
        //area 5
        if(posX < posY)
        {
            endX = BOARD_SIZE - 1 - (posY - posX);
        }
        //area 6,7,8,11
        else
        {
            endX = BOARD_SIZE - 1;
        }
    }
    //area 3,4,10
    else if(maxY > BOARD_SIZE - 1)
    {
        endX = BOARD_SIZE - 1 - (posY - posX);
    }
    //area 1,2,9,12,13
    else
    {
        endX = maxX;
    }

    //endY
    if (maxY > BOARD_SIZE - 1)
    {
        //area 6
        if(posX > posY)
        {
            endY = BOARD_SIZE - 1 - (posX - posY);
        }
        //area 3,4,5,10
        else
        {
            endY = BOARD_SIZE - 1;
        }
    }
    //area 7,8,11
    else if(maxX > BOARD_SIZE - 1)
    {
        endY = BOARD_SIZE - 1 - (posX - posY);
    }
    //area 1,2,9,12,13
    else
    {
        endY = maxY;
    }

    int j = startY;
    for(int i = startX; i < endX; i++)
    {
        if(Board_color[i][j] == TheColor && Board_color[i+1][j+1] == TheColor)
        {
            sameCount++;
        }
        else if(sameCount < WIN_COUNT - 1)
        {
            sameCount = 0;
        }
        if (j < endY)
        {
            j++;
        }
    }
    //Right top to left bottom 计算右上到左下的斜向是否胜,这里要判断所下子是否在13区域以外的其他区域,以相应的减少斜向X和Y坐标的起始位和终止位.
    //calculate start X position and Y position
    //startX
    if (minX < 0)
    {
        //area 4
        if(posX > (BOARD_SIZE - 1 - posY))
        {
            startX = minX + (maxY - (BOARD_SIZE - 1));
        }
        //area 1,2,3,9
        else
        {
            startX = 0;
        }
    }
    //area 5,6,10
    else if(maxY > BOARD_SIZE - 1)
    {
        startX = minX + (maxY - (BOARD_SIZE - 1));
    }
    //area 7,8,11,12,13
    else
    {
        startX = minX;
    }

    //startY
    if (minY < 0)
    {
        //area 7
        if((BOARD_SIZE - 1 - posX) < posY)
        {
            startY = minY + (maxX - (BOARD_SIZE - 1));
        }
        //area 1,2,8,12
        else
        {
            startY = 0;
        }
    }
    //area 5,6,11
    else if(maxX > BOARD_SIZE - 1)
    {
        startY = minY + (maxX - (BOARD_SIZE - 1));
    }
    //area 3,4,9,10,13
    else
    {
        startY = minY;
    }

    //calculate end X position and Y position
    //endX
    if (maxX > BOARD_SIZE - 1)
    {
        //area 8
        if((BOARD_SIZE - 1 - posX) > posY)
        {
            //                endX = BOARD_SIZE - 1 - ((BOARD_SIZE - 1 - posX) - posY);
            endX = maxX + minY;
        }
        //area 5,6,7,11
        else
        {
            endX = BOARD_SIZE - 1;
        }
    }
    //area 1,2,12
    else if(minY < 0)
    {
        endX = maxX + minY;
    }
    //area 3,4,9,10,13
    else
    {
        endX = maxX;
    }

    //endY
    if (maxY > BOARD_SIZE - 1)
    {
        //area 3
        if(posX < (BOARD_SIZE - 1 - posY))
        {
            endY = minX + maxY;
        }
        //area 4,5,6,10
        else
        {
            endY = BOARD_SIZE - 1;
        }
    }
    //area 1,2,9
    else if(minX < 0)
    {
        endY = minX + maxY;
    }
    //area 7,8,11,12,13
    else
    {
        endY = maxY;
    }
    int k = endY;
    for(int i = startX; i < endX; i++)
    {
        if(Board_color[i][k] == TheColor && Board_color[i+1][k-1] == TheColor)
        {
            sameCount++;
        }
        else if(sameCount < WIN_COUNT - 1)
        {
            sameCount = 0;
        }
        if (k > startY)
        {
            k--;
        }
    }

    //判断是否胜,返回boolean值
    if (sameCount >= WIN_COUNT - 1)
    {
        return true;
    }
    else
    {
        return false;
    }
}
